<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 6.3.0">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" integrity="sha256-Z1K5uhUaJXA7Ll0XrZ/0JhX4lAtZFpT6jkKrEDT0drU=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"example.com","root":"/","images":"/images","scheme":"Muse","darkmode":false,"version":"8.14.1","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":false,"style":null},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":-1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta name="description" content="前言IO模型的选择在Linux网络编程中十分重要，在Unix&#x2F;Linux环境中主要提供了五种不同的IO模型，分别是  阻塞式IO（blocking IO）； 非阻塞式IO（nonblocking IO）； IO多路复用（ IO multiplexing）； 信号驱动式IO（signal driven IO）； 异步IO（asynchronous IO）。  通常一个输入操作包含两个不同阶">
<meta property="og:type" content="article">
<meta property="og:title" content="Unix&#x2F;Linux 中的五种 IO 模型">
<meta property="og:url" content="http://example.com/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/index.html">
<meta property="og:site_name" content="JsyBlog">
<meta property="og:description" content="前言IO模型的选择在Linux网络编程中十分重要，在Unix&#x2F;Linux环境中主要提供了五种不同的IO模型，分别是  阻塞式IO（blocking IO）； 非阻塞式IO（nonblocking IO）； IO多路复用（ IO multiplexing）； 信号驱动式IO（signal driven IO）； 异步IO（asynchronous IO）。  通常一个输入操作包含两个不同阶">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="http://example.com/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/blockread.png">
<meta property="og:image" content="http://example.com/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/blockIO.png">
<meta property="og:image" content="http://example.com/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/nonBlockIO.png">
<meta property="og:image" content="http://example.com/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/iomulti.png">
<meta property="og:image" content="http://example.com/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/sigio.png">
<meta property="og:image" content="http://example.com/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/aio.png">
<meta property="og:image" content="http://example.com/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/compareIO.png">
<meta property="article:published_time" content="2021-11-20T12:20:00.000Z">
<meta property="article:modified_time" content="2022-03-16T19:43:22.984Z">
<meta property="article:author" content="SongyangJi">
<meta property="article:tag" content="Linux">
<meta property="article:tag" content="IO">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="http://example.com/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/blockread.png">


<link rel="canonical" href="http://example.com/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"http://example.com/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/","path":"2021/11/20/Unix中的五种 IO 模型/","title":"Unix/Linux 中的五种 IO 模型"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>Unix/Linux 中的五种 IO 模型 | JsyBlog</title>
  








  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">JsyBlog</p>
      <i class="logo-line"></i>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%89%8D%E8%A8%80"><span class="nav-number">1.</span> <span class="nav-text">前言</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E9%98%BB%E5%A1%9E%E5%BC%8FI-x2F-O"><span class="nav-number">2.</span> <span class="nav-text">阻塞式I&#x2F;O</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E9%9D%9E%E9%98%BB%E5%A1%9E%E5%BC%8FIO"><span class="nav-number">3.</span> <span class="nav-text">非阻塞式IO</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#I-x2F-O%E5%A4%9A%E8%B7%AF%E5%A4%8D%E7%94%A8"><span class="nav-number">4.</span> <span class="nav-text">I&#x2F;O多路复用</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BF%A1%E5%8F%B7%E9%A9%B1%E5%8A%A8%E5%BC%8FI-x2F-O"><span class="nav-number">5.</span> <span class="nav-text">信号驱动式I&#x2F;O</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%BC%82%E6%AD%A5I-x2F-O"><span class="nav-number">6.</span> <span class="nav-text">异步I&#x2F;O</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E6%80%BB%E7%BB%93"><span class="nav-number">7.</span> <span class="nav-text">总结</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%98%BB%E5%A1%9E%E4%B8%8E%E9%9D%9E%E9%98%BB%E5%A1%9E"><span class="nav-number">7.1.</span> <span class="nav-text">阻塞与非阻塞</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%90%8C%E6%AD%A5%E4%B8%8E%E5%BC%82%E6%AD%A5"><span class="nav-number">7.2.</span> <span class="nav-text">同步与异步</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%9D%9E%E9%98%BB%E5%A1%9E%E4%B8%8E%E5%BC%82%E6%AD%A5%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="nav-number">7.3.</span> <span class="nav-text">非阻塞与异步的区别</span></a></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">SongyangJi</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">251</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">45</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
          <a href="/tags/">
        <span class="site-state-item-count">109</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="Unix/Linux 中的五种 IO 模型 | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          Unix/Linux 中的五种 IO 模型
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2021-11-20 20:20:00" itemprop="dateCreated datePublished" datetime="2021-11-20T20:20:00+08:00">2021-11-20</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2022-03-17 03:43:22" itemprop="dateModified" datetime="2022-03-17T03:43:22+08:00">2022-03-17</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/IO/" itemprop="url" rel="index"><span itemprop="name">IO</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
        <h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>IO模型的选择在Linux网络编程中十分重要，在Unix&#x2F;Linux环境中主要提供了五种不同的IO模型，分别是</p>
<ol>
<li>阻塞式IO（blocking IO）；</li>
<li>非阻塞式IO（nonblocking IO）；</li>
<li>IO多路复用（ IO multiplexing）；</li>
<li>信号驱动式IO（signal driven IO）；</li>
<li>异步IO（asynchronous IO）。</li>
</ol>
<p>通常一个输入操作包含两个不同阶段：</p>
<ol>
<li>等待数据准备好</li>
<li>从内核向进程复制数据</li>
</ol>
<img src="blockread.png" style="zoom:40%;" />



<p>对于网络IO而言，对于一个网络套接字上的输入操作，第一步通常涉及到发生系统调用，用户态切换到内核态并等待数据从网络中到达，当所有等待分组到达时，数据被复制到内核中的某个缓冲区。第二步则是将数据从内核缓冲区复制到应用进程缓冲区。</p>
<p>磁盘文件的IO比较特殊，内核采用缓冲区cache加速磁盘IO请求。因而<strong>一旦请求的数据到达内核缓冲区cache，对磁盘的write()操作立即返回</strong>，而不用等待将数据写入磁盘后再返回（除非在打开文件时指定了O_SYNC标志）。与之相对应的read()操作将数据从内核缓冲区cache移动到用户的缓冲区中，如果请求的数据不在内核缓冲区cache中，<strong>内核会让进程休眠</strong>，同时执行对磁盘的读操作。</p>
<p>所以实际上在磁盘IO中，等待阶段是不存在的，因为磁盘文件并不像网络IO那样，需要等待远程传输数据。</p>
<h1 id="阻塞式I-x2F-O"><a href="#阻塞式I-x2F-O" class="headerlink" title="阻塞式I&#x2F;O"></a>阻塞式I&#x2F;O</h1><p>Linux中，默认情况下所有的socket都是阻塞的。这里有必要辨析以下阻塞和非阻塞这两个概念，这两个概念<strong>描述的是用户线程调用内核I&#x2F;O操作的方式</strong>，<strong>其中阻塞是指I&#x2F;O操作需要彻底完成后才返回到用户空间；而非阻塞则是指I&#x2F;O操作被调用后立即返回给用户一个状态值，不需要等到I&#x2F;O操作彻底完成</strong>。</p>
<p>除非特别指定，几乎所有的I&#x2F;O接口都是阻塞型的，即系统调用时不返回调用结果，只有当该系统调用获得结果或者超时出错才返回。这样的机制给网络编程带来了较大的影响，当线程因处理数据而处于阻塞状态时，线程将无法执行任何运算或者相应任何网络请求。</p>
<p><img src="/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/blockIO.png"></p>
<p>在服务器端使用阻塞I&#x2F;O模型时结合<strong>多进程&#x2F;多线程</strong>技术。</p>
<p>让每一个连接都拥有独立的进程&#x2F;线程，任何一个连接的阻塞都不会影响到其他连接。（选择多进程还是多线程并无统一标准，因为进程的开销大于线程，所以在连接数较大的情况下推荐使用多线程。而进程相较于线程具有更高的安全性，所以如果单个服务执行体需要消耗较多的CPU资源，如需要进行大规模或长时间的数据运算或文件访问推荐使用多进程）。</p>
<p>当连接数规模继续增大，无论使用多线程还是多进程都会严重占据系统资源，降低系统对外界的响应效率，线程或者进程本身也更容易陷入假死。</p>
<p>此时可以采用“线程池”或“连接池”来降低创建和销毁进程&#x2F;线程的频率，减少系统开销。</p>
<p>总之这里的线程模型实际上是<strong>一个socket对应一个进程&#x2F;线程。</strong></p>
<h1 id="非阻塞式IO"><a href="#非阻塞式IO" class="headerlink" title="非阻塞式IO"></a>非阻塞式IO</h1><p>进程把一个套接字设置成非阻塞是在通知内核：<strong>当请求的I&#x2F;O操作非得把本进程投入睡眠才能完成时，不要把本进程投入睡眠，而是返回一个错误</strong>。</p>
<p> 因此如果在打开文件时设定了O_NONBLOCK标志，则会以非阻塞方式打开文件。</p>
<p>如果I&#x2F;O系统调用不能立即完成，则会返回错误而不是阻塞进程。非阻塞式I&#x2F;O可以<strong>实现周期性检查</strong>（轮询）某个文件描述符是否可执行I&#x2F;O操作。比如，设定一个输入文件描述符为非阻塞式的，然后周期性的执行非阻塞式读操作。如果需要同时检测多个文件描述符，则将其都设为非阻塞，然后一次轮询。但是这种<strong>轮询的效率不高</strong>，在轮询频率不高的情况下，程序响应I&#x2F;O事件的延迟将难以接受。换句话说，在一个紧凑的循环中做轮询就是在<strong>浪费CPU时间</strong>，因为多数时间调用会立即出错并返回。</p>
<p><img src="/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/nonBlockIO.png"></p>
<blockquote>
<p>对于不能满足非阻塞式I&#x2F;O操作，System V会返回EAGAIN错误而源于Berkeley的4.3BSD返回EWOULDBLOCK。如今大多数系统都把这两个错误码定义为相同的值。（可查看<code>&lt;sys/errno.h&gt;</code>）</p>
</blockquote>
<h1 id="I-x2F-O多路复用"><a href="#I-x2F-O多路复用" class="headerlink" title="I&#x2F;O多路复用"></a>I&#x2F;O多路复用</h1><p><img src="/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/iomulti.png"></p>
<p>I&#x2F;O多路复用（也叫做事件驱动I&#x2F;O）通过系统调用<code>select()</code>、<code>poll</code>、或者<code>epoll()</code>实现<strong>进程同时检查多个文件描述符</strong>，以找出其中任何一个是否可执行I&#x2F;O操作。通过上图可以看出I&#x2F;O多路复用与阻塞I&#x2F;O模型差别并不大，事实上还要差一些，因为这里使用了两个系统调用而阻塞I&#x2F;O只是用了一个系统调用。</p>
<p>但是<strong>I&#x2F;O多路复用的优势是单个线程&#x2F;进程可以同时处理多个连接</strong>。因此如果处理的连接数不是特别多的情况下使用I&#x2F;O多路复用模型的web server不一定比使用多线程技术的阻塞I&#x2F;O模型好。</p>
<p><strong>事实上，这种IO多路复用方式实际上也正是各种高性能网络框架以及高性能的网络服务器使用的最多的模式。</strong>所以，这也是我们学习的重点。</p>
<h1 id="信号驱动式I-x2F-O"><a href="#信号驱动式I-x2F-O" class="headerlink" title="信号驱动式I&#x2F;O"></a>信号驱动式I&#x2F;O</h1><p><img src="/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/sigio.png"></p>
<p>信号驱动I&#x2F;O中，当文件描述符上可执行I&#x2F;O操作时，进程请求内核为自己发送一个信号，之后进程可以执行其他任务直到I&#x2F;O就绪为止，此时内核会发送信号给进程。建立一个针对套接字的信号驱动式I&#x2F;O需要进程执行以下三个步骤：</p>
<ol>
<li>建立<code>SIGIO</code>信号处理函数</li>
<li>设置该套接字的属主，通常使用<code>fcntl</code>的<code>F_SETOWN</code>命令设置</li>
<li>开启该套接字的信号驱动式I&#x2F;O，通常通过使用<code>fcnt</code>的<code>F_SETFL</code>命令打开<code>O_ASYNC</code>标志完成</li>
</ol>
<p>使用信号驱动式I&#x2F;O模型的主要优点是<strong>在等待数据到达期间，进程不会被阻塞</strong>。</p>
<p><strong>信号驱动式I&#x2F;O的应用</strong></p>
<ul>
<li><p>对于UDP上的使用比较简单，<code>SIGIO</code>信号只有在数据报到达套接字或者套接字发生异步错误时产生。因此当捕获对于某个UDP套接字的<code>SIGIO</code>信号时，我们调用recvfrom或者读入到达的数据报或者获取发生的异步错误。</p>
</li>
<li><p><strong>信号驱动式I&#x2F;O对于TCP套接字几乎无用</strong>，主要原因是<code>SIGIO</code>信号产生会过于频繁，并且其出现并没有告知我们发生了什么事件。比如，当一个进程既读又写一个TCP套接字时，当有数据到达或者当前写出的数据得到确认时，<code>SIGIO</code>信号都会产生，而信号处理函数无法区分这两种情况。 <strong>应该只考虑对监听TCP套接字使用<code>SIGIO</code>，因为对于监听TCP套接字产生<code>SIGIO</code>的唯一条件是某个新连接的完成</strong>。</p>
</li>
</ul>
<h1 id="异步I-x2F-O"><a href="#异步I-x2F-O" class="headerlink" title="异步I&#x2F;O"></a>异步I&#x2F;O</h1><p><img src="/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/aio.png"></p>
<p>对于I&#x2F;O操作主要有两种分别是异步I&#x2F;O和同步I&#x2F;O，对于同步I&#x2F;O会导致请求进程阻塞，直到I&#x2F;O操作完成，即必须等待I&#x2F;O操作完成以后控制权才返回给用户进程；而异步I&#x2F;O不会导致请求进程阻塞，即无需等待I&#x2F;O操作完成就将控制权返回给用户进程。</p>
<ul>
<li><p>异步I&#x2F;O模型的工作机制</p>
<p>告知内核启动某个操作，并让内核在整个操作（包括将数据从内核复制到进程缓冲区）完成后通知我们。主要方式是调用<code>aio_read</code>函数向内核传递描述符、缓冲区指针、缓冲区大小（与read相同的三个参数）和文件偏移，并告知内核当整个操作完成时如何通知用户进程。该系统调用立即返回，在等待I&#x2F;O完成期间进程不被阻塞。</p>
</li>
<li><p>与信号驱动式I&#x2F;O模型的区别<br>信号驱动式I&#x2F;O是由内核告诉我们<strong>何时可以启动一个I&#x2F;O操作</strong>，而异步I&#x2F;O模型则是由内核通知我们<strong>I&#x2F;O操作何时完成</strong>。</p>
</li>
</ul>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>5种IO模式的对比：</p>
<p><img src="/2021/11/20/Unix%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%20IO%20%E6%A8%A1%E5%9E%8B/compareIO.png"></p>
<p>前4中模型的区别主要在于第一阶段，因为它们的第二阶段都是一样的：在数据从内核复制到用户空间的缓冲区期间，进程阻塞于<code>read</code>调用。</p>
<p>相反异步模型在这两个阶段都要进行处理，在完成的时候才会通知调用者已经完成。</p>
<h2 id="阻塞与非阻塞"><a href="#阻塞与非阻塞" class="headerlink" title="阻塞与非阻塞"></a>阻塞与非阻塞</h2><p>阻塞与非阻塞的区分是在第一阶段，也就是等待数据报有没有到的情况。</p>
<h2 id="同步与异步"><a href="#同步与异步" class="headerlink" title="同步与异步"></a>同步与异步</h2><ul>
<li><p>同步I&#x2F;O会导致请求进程阻塞，直到I&#x2F;O操作完成，即必须等待I&#x2F;O操作完成以后控制权才返回给用户进程；</p>
</li>
<li><p>异步I&#x2F;O不会导致请求进程阻塞，即无需等待I&#x2F;O操作完成就将控制权返回给用户进程。</p>
</li>
</ul>
<h2 id="非阻塞与异步的区别"><a href="#非阻塞与异步的区别" class="headerlink" title="非阻塞与异步的区别"></a>非阻塞与异步的区别</h2><p>在non-blocking IO中，虽然进程大部分时间都不会被block，但是它仍然要求进程去主动的check，并且当数据准备完成以后，也需要进程主动的再次调用recvfrom来将数据拷贝到用户内存。而asynchronous IO则完全不同。它就像是用户进程将整个IO操作交给了他人（kernel）完成，然后他人做完后发信号通知。在此期间，用户进程不需要去检查IO操作的状态，也不需要主动的去拷贝数据。</p>

    </div>

    
    
    

    <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/Linux/" rel="tag"># Linux</a>
              <a href="/tags/IO/" rel="tag"># IO</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/2021/11/18/UDP/" rel="prev" title="UDP-用户数据报协议">
                  <i class="fa fa-chevron-left"></i> UDP-用户数据报协议
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/2021/11/20/socket/" rel="next" title="Socket编程 —— 使用 select、poll、epoll">
                  Socket编程 —— 使用 select、poll、epoll <i class="fa fa-chevron-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


<div class="copyright">
  &copy; 
  <span itemprop="copyrightYear">2023</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">SongyangJi</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/muse/" rel="noopener" target="_blank">NexT.Muse</a> 强力驱动
  </div>

    </div>
  </footer>

  
  <div class="toggle sidebar-toggle" role="button">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>
  <div class="sidebar-dimmer"></div>
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/schemes/muse.js"></script><script src="/js/next-boot.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.1/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>





  





</body>
</html>
